package com.bestcem.xm.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.AuthErrorCodeEnum;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.user.constant.UserCacheKeyConstant;
import com.bestcem.xm.user.dao.OrganizationDao;
import com.bestcem.xm.user.dao.UserAccountDao;
import com.bestcem.xm.user.entity.mysql.Organization;
import com.bestcem.xm.user.entity.pojo.UserDO;
import com.bestcem.xm.user.enums.OrganizationStatusEnum;
import com.bestcem.xm.user.grpc.client.BaseWechatworkGrpcService;
import com.bestcem.xm.user.grpc.client.PackageGrpcService;
import com.bestcem.xm.user.grpc.client.UserWechatGrpcService;
import com.bestcem.xm.user.grpc.client.UserWechatWorkGrpcService;
import com.bestcem.xm.user.grpc.client.dto.PackageDTO;
import com.bestcem.xm.user.grpc.client.dto.WechatUserDetailDTO;
import com.bestcem.xm.user.grpc.client.dto.WechatworkEnterpriseInfoDTO;
import com.bestcem.xm.user.grpc.client.dto.redis.WxCacheDTO;
import com.bestcem.xm.user.service.*;
import com.bestcem.xm.user.service.dto.user.*;
import com.bestcem.xm.user.service.dto.wechatwork.WechatWorkUnbindDTO;
import com.bestcem.xm.user.service.third.GrowingIOService;
import com.bestcem.xm.user.util.business.UserCacheUtil;
import com.bestcem.xm.user.util.business.UserJwtTokenUtil;
import com.bestcem.xm.user.util.business.UserUtil;
import com.bestcem.xm.user.util.business.captcha.CaptchaUtil;
import com.bestcem.xm.user.util.convert.UserConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 * 企业微信相关服务
 *
 * @author XiaoYunSong <ys.xiao@idiaoyan.com>
 * @version v1.0
 * @date 2022/7/18 15:12
 */
@Slf4j
@Service
public class UserWxWorkServiceImpl implements UserWxWorkService {

    public static final String NAME_OR_PASSWORD_NOT_TRUE = "user_name or password not true.";

    @Autowired
    private UserService userService;

    @Autowired
    private UserCacheUtil userCacheUtil;

    @Autowired
    private CaptchaUtil captchaUtil;

    @Resource
    private UserAuthService userAuthService;
    @Autowired
    private GrowingIOService growingIoService;
    @Autowired
    private PackageGrpcService packageGrpcService;
    @Resource
    private OrganizationService organizationService;
    @Resource
    private UserBusinessService userBusinessService;

    @Resource
    private UserAccountDao userAccountDao;
    @Resource
    private OrganizationDao userOrganizationDao;

    @Resource
    private BaseWechatworkGrpcService baseWechatworkGrpcService;
    @Resource(name = "userUserWechatWorkGrpcService")
    private UserWechatWorkGrpcService userWechatWorkGrpcService;

    @Resource
    private UserConvert userConvert;
    @Resource
    private UserUtil userUtil;
    @Resource
    private UserJwtTokenUtil userJwtTokenUtil;

    @Resource
    private UserWechatGrpcService userWechatGrpcService;


    @Override
    public ServiceResult<Object> tokenView(WeChatTokenDTO weChatTokenDTO, HttpServletResponse response) {
        // 缓存wxwork_mini_session:{session_id}
        WechatUserDetailDTO detailDTO = userWechatWorkGrpcService.getWxworkUserDetail(weChatTokenDTO.getSessionId(), UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX);

        WechatworkEnterpriseInfoDTO enterpriseinfo = baseWechatworkGrpcService.getOneEnterpriseinfo(detailDTO.getCorpid(), null);
        if (Objects.isNull(enterpriseinfo)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "corpid is Notfind.");
        }

        List<UserDTO> userDTOList = userService.getUserListByUsernameOrEmailOrPhone(null, null, weChatTokenDTO.getUsername(), weChatTokenDTO.getUsername().toLowerCase());

        if (org.apache.commons.collections4.CollectionUtils.isEmpty(userDTOList)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not found.");
        }
        // 密码正确的用户
        List<UserDTO> correctUserList = new ArrayList<>();
        for (UserDTO userDTO : userDTOList) {
            ServiceResult<Boolean> checkPassword = userAuthService.checkPassword(userDTO.getUserId(), weChatTokenDTO.getPassword());
            if (checkPassword.isSuccess() && Boolean.TRUE.equals(checkPassword.getData())) {
                correctUserList.add(userDTO);
            }
        }

        // 账户不存在,走注册流程
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(correctUserList)) {
            captchaUtil.setLoginCaptcha(response, weChatTokenDTO.getUsername(), weChatTokenDTO.getIp());
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NAME_NOT_EXISTS, NAME_OR_PASSWORD_NOT_TRUE);
        }
        if (correctUserList.size() == 1) {
            UserDTO userDTO = correctUserList.get(0);
            captchaUtil.clearLoginCaptcha(response, userDTO.getUserName(), weChatTokenDTO.getIp());
            ServiceResult<OrganizationDTO> organizationResult = organizationService.selectByPrimaryKey(userDTO.getOrgId());
            OrganizationDTO organizationDTO = organizationResult.getData();
            // 账户密码不匹配
            if (Objects.isNull(organizationDTO) || !OrganizationStatusEnum.ACTIVATED.getStatus().equals(organizationDTO.getStatus())) {
                return ServiceResult.fail(AuthErrorCodeEnum.USER_NAME_NOT_EXISTS, NAME_OR_PASSWORD_NOT_TRUE);
            }
            // 判断租户是否到期
            if (Objects.isNull(organizationDTO.getPackageExpireTime()) &&
                    new Date().after(organizationDTO.getPackageExpireTime())) {
                return ServiceResult.fail(AuthErrorCodeEnum.ORG_EXPIRE, DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.NORM_DATETIME_PATTERN));
            }

            if (StringUtils.isBlank(enterpriseinfo.getOrgCode()) || !organizationDTO.getCode().equals(enterpriseinfo.getOrgCode())) {
                return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "账号租户信息与当前企业微信团队不符");
            }

            WechatworkEnterpriseInfoDTO status = baseWechatworkGrpcService.getOneEnterpriseinfo(null, organizationDTO.getCode());
            if (Objects.nonNull(status) && !status.getCorpid().equals(enterpriseinfo.getCorpid())) {
                return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "该账号已绑定");
            }

            // 判断是否需要更换绑定qyWxOpenUserid
            if (!userDTO.getQyWxOpenUserid().equals(detailDTO.getQyWxOpenUserid())) {
                userService.updateUserByQyWxOpenUserid(detailDTO.getQyWxOpenUserid());

                userDTO.setQyWxUserid(detailDTO.getUserId());
                userDTO.setQyWxOpenUserid(detailDTO.getQyWxOpenUserid());
                userDTO.setQyWxName(detailDTO.getName());
                userService.updateById(userDTO);
            }
            // 更新最后登录时间
            userAuthService.updateUserLastLoginTime(userDTO.getUserId());

            // 判断是否是企业微信管理员及 是否需要对corpid和org_code进行绑定
            if (Boolean.TRUE.equals(detailDTO.getManager()) && StringUtils.isBlank(enterpriseinfo.getOrgCode())) {
                baseWechatworkGrpcService.updateEnterpriseinfo(null, enterpriseinfo.getCorpid(), userDTO.getOrgId(), organizationDTO.getCode());
            }
            captchaUtil.clearLoginCaptcha(response, userDTO.getUserName(), weChatTokenDTO.getIp());

            PackageDTO packageDTO = packageGrpcService.getById(organizationDTO.getPackageId());
            GrowingioDTO growingioDTO = growingIoService.getUserProperty(userDTO, organizationDTO, packageDTO.getName());
            // 设置AutoDTO build信息
            AuthDTO.AuthDTOBuilder builder = AuthDTO.builder();
            // 设置公司信息
            builder.orgId(organizationDTO.getOrgId());
            builder.orgCode(organizationDTO.getCode());
            builder.packageExpireTime(DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.YYYY_MM_DD));
            // 设置用户信息
            builder.userId(userDTO.getUserId());
            builder.realName(userDTO.getName());
            builder.avatar(userDTO.getAvatar());

            // 设置用户是否是系统管理员和高级管理员
            builder.superRole(userBusinessService.checkSuper(userDTO.getUserId(), userDTO.getOrgId()).getData());
            builder.senior(userBusinessService.checkSenior(userDTO.getUserId(), userDTO.getOrgId()).getData());

            // 生成jwt
            String token = userJwtTokenUtil.generateToken(builder.build());
            String refreshToken = userJwtTokenUtil.generateRefreshToken(organizationDTO.getCode(), userDTO.getUserId());

            WxLoginDTO wxLoginDTO = new WxLoginDTO();
            wxLoginDTO.setToken(token);
            wxLoginDTO.setRefreshToken(refreshToken);
            wxLoginDTO.setGrowingio(growingioDTO);
            wxLoginDTO.setOrgCode(organizationDTO.getCode());
            return ServiceResult.success(userConvert.wxLoginDTO2VO(wxLoginDTO));
        } else {
            List<OrgCodeDTO> orgCodeDTOList = new ArrayList<>();
            captchaUtil.clearLoginCaptcha(response, weChatTokenDTO.getUsername(), weChatTokenDTO.getIp());
            for (UserDTO userDTO : correctUserList) {
                ServiceResult<OrganizationDTO> organizationResult = organizationService.selectByPrimaryKey(userDTO.getOrgId());
                OrganizationDTO organizationDTO = organizationResult.getData();
                if (Objects.isNull(organizationDTO)) {
                    captchaUtil.setLoginCaptcha(response, weChatTokenDTO.getUsername(), weChatTokenDTO.getIp());
                    return ServiceResult.fail(AuthErrorCodeEnum.USER_NAME_NOT_EXISTS, NAME_OR_PASSWORD_NOT_TRUE);
                }
                OrgCodeDTO orgCodeDTO = new OrgCodeDTO();
                orgCodeDTO.setOrgCode(organizationDTO.getCode());
                orgCodeDTO.setOrgName(organizationDTO.getName());
                orgCodeDTO.setOrgId(organizationDTO.getOrgId());
                orgCodeDTO.setUserName(userDTO.getUserName());
                orgCodeDTOList.add(orgCodeDTO);
            }
            WxMultiOrgDTO wxMultiOrgDTO = new WxMultiOrgDTO();
            wxMultiOrgDTO.setMultiOrg(true);
            wxMultiOrgDTO.setOrgCodeList(orgCodeDTOList);
            wxMultiOrgDTO.setSessionId(weChatTokenDTO.getSessionId());
            return ServiceResult.success(wxMultiOrgDTO);
        }
    }


    @Override
    public ServiceResult<WeChatCodeResultDTO> weChatCodeTokenView(WeChatCodeTokenDTO codeToken, HttpServletRequest request) {
        String orgCode = "";
        if (StringUtils.isNotBlank(codeToken.getOrgCode())) {
            orgCode = codeToken.getOrgCode();
        } else {
            ServiceResult<String> corpCode = userUtil.getCorpCode(null, request.getServerName());
            if (!corpCode.isSuccess()) {
                return ServiceResult.fail(corpCode.getErrorData(), corpCode.getMsg());
            }
            orgCode = corpCode.getData();
        }

        // wxwork_mini_session:{session_id}
        WechatUserDetailDTO detailDTO = userWechatWorkGrpcService.getWxworkUserDetail(codeToken.getSessionId(), UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX);

        // 获取wechatwork_enterprise_info
        WechatworkEnterpriseInfoDTO enterpriseinfo = baseWechatworkGrpcService.getOneEnterpriseinfo(detailDTO.getCorpid(), null);

        if (Objects.isNull(enterpriseinfo)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "corpid is Notfind.");
        }

        // 如果绑定过，验证org_code 是否一致，  未绑定过判断此用户是否是管理员
        if (StringUtils.isBlank(enterpriseinfo.getOrgCode()) ||
                !enterpriseinfo.getOrgCode().equals(orgCode)) {
            return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "账号租户信息与当前企微团队不符");
        }
        ServiceResult<OrganizationDTO> result = organizationService.selectByOrgCode(orgCode);
        OrganizationDTO organizationDTO = result.getData();
        if (Objects.isNull(organizationDTO)) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_NOT_EXISTS, NAME_OR_PASSWORD_NOT_TRUE);
        }
        if (Objects.nonNull(organizationDTO.getPackageExpireTime())
                && new Date().after(organizationDTO.getPackageExpireTime())) {
            return ServiceResult.fail(AuthErrorCodeEnum.ORG_EXPIRE, DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.NORM_DATETIME_PATTERN));
        }

        List<UserDTO> userList = userService.getUserListByUsernameOrEmailOrPhone(organizationDTO.getOrgId(), codeToken.getUsername(), codeToken.getUsername(), codeToken.getUsername().toLowerCase());
        if (org.apache.commons.collections4.CollectionUtils.isEmpty(userList)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not found");
        }
        UserDTO userDTO = userList.get(0);
        ServiceResult<Boolean> checkPassword = userAuthService.checkPassword(userDTO.getUserId(), codeToken.getPassword());
        if (!checkPassword.isSuccess() && checkPassword.getData().equals(false)) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user_name or password not true");
        }

        // 在绑定open_userid及corpid与org_code绑定的情况下，不允许在其他团队登陆
        WechatworkEnterpriseInfoDTO status = baseWechatworkGrpcService.getOneEnterpriseinfo(null, organizationDTO.getCode());
        if (Objects.nonNull(status) && !status.getCorpid().equals(enterpriseinfo.getCorpid())) {
            return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "该账户已被绑定");
        }
        if (Objects.isNull(codeToken.getBindFlag())) {
            codeToken.setBindFlag(Boolean.FALSE);
        }
        // 判断是否是企业微信管理员
        if (Boolean.TRUE.equals(detailDTO.getManager() && codeToken.getBindFlag()) && StringUtils.isBlank(enterpriseinfo.getOrgCode())) {
            baseWechatworkGrpcService.updateEnterpriseinfo(enterpriseinfo.getId(), null, organizationDTO.getOrgId(), orgCode);
        }

        // 判断是否需要换绑open_userid
        if (log.isInfoEnabled()) {
            log.info(userDTO.getQyWxOpenUserid() + "======已经绑定的用户信息945");
        }

        // 不管绑定与否，只要登录了，就先拿用户信息.退出登录，清空用户信息
        // wxwork_mini_session:{session_id}
        // WechatUserDetailDTO optionData = userWechatWorkGrpcService.getWxworkUserDetail(codeToken.getSessionId(), UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX);
        WxCacheDTO optionData = userWechatGrpcService.getWxworkSessionInfo(codeToken.getSessionId());
        UserDTO check = new UserDTO();
        check.setOrgId(userDTO.getOrgId());
        check.setUserName(userDTO.getUserName());
        ServiceResult<List<UserDTO>> userResult = userService.listByCondition(check);
        if (!userResult.isSuccess() || org.apache.commons.collections4.CollectionUtils.isEmpty(userResult.getData())) {
            return ServiceResult.fail(AuthErrorCodeEnum.USER_NOT_EXISTS, "user not found");
        }
        UserDTO user = userResult.getData().get(0);
        optionData.setEmail(StringUtils.isNotBlank(user.getEmail()) ? user.getEmail() : "");
        optionData.setPhone(StringUtils.isNotBlank(user.getPhone()) ? user.getPhone() : "");
        //optionData.setWxNickname(StringUtils.isNotBlank(user.getWxNickname()) ? user.getWxNickname() : "");
        optionData.setName(StringUtils.isNotBlank(user.getName()) ? user.getName() : "");

        // 缓存 wxwork_mini_session
        // userWechatWorkGrpcService.cacheWxworkSessionInfo(codeToken.getSessionId(), optionData);
        userWechatGrpcService.cacheWxworkSessionInfo(codeToken.getSessionId(), optionData);
        if (!detailDTO.getQyWxOpenUserid().equals(userDTO.getQyWxOpenUserid())) {
            userService.updateUserByQyWxOpenUserid(detailDTO.getQyWxOpenUserid());
            UserDTO updateUser = new UserDTO();
            updateUser.setUserId(userDTO.getUserId());
            updateUser.setQyWxUserid(detailDTO.getUserId());
            updateUser.setQyWxOpenUserid(detailDTO.getQyWxOpenUserid());
            updateUser.setQyWxName(detailDTO.getName());
            userService.updateById(updateUser);

            // 更新最后登录时间
            userAuthService.updateUserLastLoginTime(userDTO.getUserId());
        }
        // 设置AutoDTO build信息
        AuthDTO.AuthDTOBuilder builder = AuthDTO.builder();
        // 设置公司信息
        builder.orgId(organizationDTO.getOrgId());
        builder.orgCode(organizationDTO.getCode());
        builder.packageExpireTime(DateUtil.convertDteToString(organizationDTO.getPackageExpireTime(), DateUtil.YYYY_MM_DD));
        // 设置用户信息
        builder.userId(userDTO.getUserId());
        builder.realName(userDTO.getName());
        builder.avatar(userDTO.getAvatar());

        // 设置用户是否是系统管理员和高级管理员
        builder.superRole(userBusinessService.checkSuper(userDTO.getUserId(), userDTO.getOrgId()).getData());
        builder.senior(userBusinessService.checkSenior(userDTO.getUserId(), userDTO.getOrgId()).getData());

        // 生成jwt
        String token = userJwtTokenUtil.generateToken(builder.build());
        String refreshToken = userJwtTokenUtil.generateRefreshToken(organizationDTO.getCode(), userDTO.getUserId());

        List<String> tokenList = new ArrayList<>();
        tokenList.add(token);
        // 拿到当前租户下面的其他用户的登录token
        List<String> tokens = JSON.parseArray(userCacheUtil.get(UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX, orgCode), String.class);
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(tokens)) {
            tokenList.addAll(tokens);
        }
        userCacheUtil.setEx(UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX + ":" + orgCode, tokenList.toString(), 3600 * 48L, TimeUnit.SECONDS);

        PackageDTO packageDTO = packageGrpcService.getById(organizationDTO.getPackageId());
        GrowingioDTO growingioDTO = growingIoService.getUserProperty(userDTO, organizationDTO, packageDTO.getName());
        WeChatCodeResultDTO resultDTO = new WeChatCodeResultDTO();
        resultDTO.setOrgCode(orgCode);
        resultDTO.setGrowingio(growingioDTO);
        resultDTO.setToken(token);
        resultDTO.setRefreshToken(refreshToken);
        return ServiceResult.success(resultDTO);
    }


    @Override
    public ServiceResult<WechatWorkUnbindDTO> unbindUser(String userId) {
        UserDO userDO = userAccountDao.selectByPrimaryKey(userId);
        Organization orgDO = userOrganizationDao.findById(userDO.getOrgId());
        WechatworkEnterpriseInfoDTO wechatWork = baseWechatworkGrpcService.getOneEnterpriseinfo(null, orgDO.getCode());
        if (Objects.isNull(wechatWork)) {
            return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "该企业微信未绑定或被其他管理员解绑");
        }

        // 拿到当前租户下面的其他用户的登录token
        List<String> tokens = JSON.parseArray(userCacheUtil.get(UserCacheKeyConstant.WXWORK_MINI_SESSION_PREFIX, orgDO.getCode()), String.class);
        if (!CollectionUtils.isEmpty(tokens)) {
            for (String token : tokens) {
                // 与access_key过期时间一致
                userJwtTokenUtil.setJwtInvalid(token);
            }
        }
        // 清空 python 方面的记录的企微和租户的绑定信息清除
        boolean unbindResult = userWechatWorkGrpcService.unbindWxworkCorp(wechatWork.getCorpid());
        if (!unbindResult) {
            log.error("[User] 企业微信解绑失败 {}", userId);
            return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "企业微信解绑失败");
        }

        // 把租户下面所有用户的企微都解绑
        try {
            userAccountDao.unbindWechatWorkByOrgId(userDO.getOrgId());
        } catch (Exception e) {
            log.error("[User] 企业微信用户批量解绑失败 {}", userId, e);
            // 解绑失败时回滚租户的绑定信息
            baseWechatworkGrpcService.updateEnterpriseinfo(null, wechatWork.getCorpid(), orgDO.getOrgId(), orgDO.getCode());
            return ServiceResult.fail(AuthErrorCodeEnum.WX_WORK_BIND_ERROR, "企业微信解绑失败");
        }
        // 清空 python 方面的记录的企微公司信息缓存
        userWechatWorkGrpcService.clearWxworkCorpTokenCache(wechatWork.getCorpid());
        return ServiceResult.success(new WechatWorkUnbindDTO(userId));
    }
}
